import { CanActivate, ExecutionContext, Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import type { Request } from 'express';
import type { Redis } from 'ioredis';
import { Inject } from '@nestjs/common';

@Injectable()
export class IpRateLimitGuard implements CanActivate {
  constructor(
    private readonly configService: ConfigService,
    @Inject('RATE_LIMIT_REDIS') private readonly client: Redis,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const req = context.switchToHttp().getRequest<Request>();
    const ip = this.getClientIp(req);
    const ttl = Number(this.configService.get('RATE_TTL') ?? 60);
    const limit = Number(this.configService.get('RATE_LIMIT') ?? 100);
    const prefix = this.configService.get('RATE_PREFIX') ?? 'rate:ip';

    const nowWindow = Math.floor(Date.now() / (ttl * 1000));
    const key = `${prefix}:${ip}:${nowWindow}`;

    const count = await this.client.incr(key);
    if (count === 1) {
      await this.client.expire(key, ttl);
    }

    if (count > limit) {
      throw new HttpException('Too many requests', HttpStatus.TOO_MANY_REQUESTS);
    }

    return true;
  }

  private getClientIp(req: Request): string {
    const xff = (req.headers['x-forwarded-for'] as string) || '';
    const forwardedIp = xff.split(',').map(s => s.trim()).find(Boolean);
    const ip = forwardedIp || req.ip || (req.connection as any)?.remoteAddress || '';
    return ip;
  }
}


